home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2018 January / PCgo 01-2018 CD-ROM Germany.iso / nw.pak / Unnamed File 000161.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  16.8 KB  |  524 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. // // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  6. // Use of this source code is governed by a BSD-style license that can be
  7. // found in the LICENSE file.
  8.  
  9. /**
  10.  * @fileoverview Assertion support.
  11.  */
  12.  
  13. /**
  14.  * Verify |condition| is truthy and return |condition| if so.
  15.  * @template T
  16.  * @param {T} condition A condition to check for truthiness.  Note that this
  17.  *     may be used to test whether a value is defined or not, and we don't want
  18.  *     to force a cast to Boolean.
  19.  * @param {string=} opt_message A message to show on failure.
  20.  * @return {T} A non-null |condition|.
  21.  */
  22. function assert(condition, opt_message) {
  23.   'use strict';
  24.   if (!condition) {
  25.     var msg = 'Assertion failed';
  26.     if (opt_message)
  27.       msg = msg + ': ' + opt_message;
  28.     throw new Error(msg);
  29.   }
  30.   return condition;
  31. }
  32.  
  33. /**
  34.  * Call this from places in the code that should never be reached.
  35.  *
  36.  * For example, handling all the values of enum with a switch() like this:
  37.  *
  38.  *   function getValueFromEnum(enum) {
  39.  *     switch (enum) {
  40.  *       case ENUM_FIRST_OF_TWO:
  41.  *         return first
  42.  *       case ENUM_LAST_OF_TWO:
  43.  *         return last;
  44.  *     }
  45.  *     assertNotReached();
  46.  *     return document;
  47.  *   }
  48.  *
  49.  * This code should only be hit in the case of serious programmer error or
  50.  * unexpected input.
  51.  *
  52.  * @param {string=} opt_message A message to show when this is hit.
  53.  */
  54. function assertNotReached(opt_message) {
  55.   throw new Error(opt_message || 'Unreachable code hit');
  56. }
  57.  
  58. /**
  59.  * @param {*} value The value to check.
  60.  * @param {function(new: T, ...)} type A user-defined constructor.
  61.  * @param {string=} opt_message A message to show when this is hit.
  62.  * @return {T}
  63.  * @template T
  64.  */
  65. function assertInstanceof(value, type, opt_message) {
  66.   if (!(value instanceof type)) {
  67.     throw new Error(opt_message ||
  68.                     value + ' is not a[n] ' + (type.name || typeof type));
  69.   }
  70.   return value;
  71. }
  72.  
  73.  
  74. /**
  75.  * Alias for document.getElementById.
  76.  * @param {string} id The ID of the element to find.
  77.  * @return {HTMLElement} The found element or null if not found.
  78.  */
  79. function $(id) {
  80.   return document.getElementById(id);
  81. }
  82.  
  83. /**
  84.  * Add an accessible message to the page that will be announced to
  85.  * users who have spoken feedback on, but will be invisible to all
  86.  * other users. It's removed right away so it doesn't clutter the DOM.
  87.  * @param {string} msg The text to be pronounced.
  88.  */
  89. function announceAccessibleMessage(msg) {
  90.   var element = document.createElement('div');
  91.   element.setAttribute('aria-live', 'polite');
  92.   element.style.position = 'relative';
  93.   element.style.left = '-9999px';
  94.   element.style.height = '0px';
  95.   element.innerText = msg;
  96.   document.body.appendChild(element);
  97.   window.setTimeout(function() {
  98.     document.body.removeChild(element);
  99.   }, 0);
  100. }
  101.  
  102. /**
  103.  * Calls chrome.send with a callback and restores the original afterwards.
  104.  * @param {string} name The name of the message to send.
  105.  * @param {!Array} params The parameters to send.
  106.  * @param {string} callbackName The name of the function that the backend calls.
  107.  * @param {!Function} callback The function to call.
  108.  */
  109. function chromeSend(name, params, callbackName, callback) {
  110.   var old = global[callbackName];
  111.   global[callbackName] = function() {
  112.     // restore
  113.     global[callbackName] = old;
  114.  
  115.     var args = Array.prototype.slice.call(arguments);
  116.     return callback.apply(global, args);
  117.   };
  118.   chrome.send(name, params);
  119. }
  120.  
  121. /**
  122.  * Returns the scale factors supported by this platform.
  123.  * @return {Array} The supported scale factors.
  124.  */
  125. function getSupportedScaleFactors() {
  126.   var supportedScaleFactors = [];
  127.   if (cr.isMac || cr.isChromeOS) {
  128.     supportedScaleFactors.push(1);
  129.     supportedScaleFactors.push(2);
  130.   } else {
  131.     // Windows must be restarted to display at a different scale factor.
  132.     supportedScaleFactors.push(window.devicePixelRatio);
  133.   }
  134.   return supportedScaleFactors;
  135. }
  136.  
  137. /**
  138.  * Generates a CSS url string.
  139.  * @param {string} s The URL to generate the CSS url for.
  140.  * @return {string} The CSS url string.
  141.  */
  142. function url(s) {
  143.   // http://www.w3.org/TR/css3-values/#uris
  144.   // Parentheses, commas, whitespace characters, single quotes (') and double
  145.   // quotes (") appearing in a URI must be escaped with a backslash
  146.   var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
  147.   // WebKit has a bug when it comes to URLs that end with \
  148.   // https://bugs.webkit.org/show_bug.cgi?id=28885
  149.   if (/\\\\$/.test(s2)) {
  150.     // Add a space to work around the WebKit bug.
  151.     s2 += ' ';
  152.   }
  153.   return 'url("' + s2 + '")';
  154. }
  155.  
  156. /**
  157.  * Returns the URL of the image, or an image set of URLs for the profile avatar.
  158.  * Default avatars have resources available for multiple scalefactors, whereas
  159.  * the GAIA profile image only comes in one size.
  160.  *
  161.  * @param {string} path The path of the image.
  162.  * @return {string} The url, or an image set of URLs of the avatar image.
  163.  */
  164. function getProfileAvatarIcon(path) {
  165.   var chromeThemePath = 'chrome://theme';
  166.   var isDefaultAvatar =
  167.       (path.slice(0, chromeThemePath.length) == chromeThemePath);
  168.   return isDefaultAvatar ? imageset(path + '@scalefactorx'): url(path);
  169. }
  170.  
  171. /**
  172.  * Generates a CSS -webkit-image-set for a chrome:// url.
  173.  * An entry in the image set is added for each of getSupportedScaleFactors().
  174.  * The scale-factor-specific url is generated by replacing the first instance of
  175.  * 'scalefactor' in |path| with the numeric scale factor.
  176.  * @param {string} path The URL to generate an image set for.
  177.  *     'scalefactor' should be a substring of |path|.
  178.  * @return {string} The CSS -webkit-image-set.
  179.  */
  180. function imageset(path) {
  181.   var supportedScaleFactors = getSupportedScaleFactors();
  182.  
  183.   var replaceStartIndex = path.indexOf('scalefactor');
  184.   if (replaceStartIndex < 0)
  185.     return url(path);
  186.  
  187.   var s = '';
  188.   for (var i = 0; i < supportedScaleFactors.length; ++i) {
  189.     var scaleFactor = supportedScaleFactors[i];
  190.     var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor +
  191.         path.substr(replaceStartIndex + 'scalefactor'.length);
  192.  
  193.     s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
  194.  
  195.     if (i != supportedScaleFactors.length - 1)
  196.       s += ', ';
  197.   }
  198.   return '-webkit-image-set(' + s + ')';
  199. }
  200.  
  201. /**
  202.  * Parses query parameters from Location.
  203.  * @param {Location} location The URL to generate the CSS url for.
  204.  * @return {Object} Dictionary containing name value pairs for URL
  205.  */
  206. function parseQueryParams(location) {
  207.   var params = {};
  208.   var query = unescape(location.search.substring(1));
  209.   var vars = query.split('&');
  210.   for (var i = 0; i < vars.length; i++) {
  211.     var pair = vars[i].split('=');
  212.     params[pair[0]] = pair[1];
  213.   }
  214.   return params;
  215. }
  216.  
  217. /**
  218.  * Creates a new URL by appending or replacing the given query key and value.
  219.  * Not supporting URL with username and password.
  220.  * @param {Location} location The original URL.
  221.  * @param {string} key The query parameter name.
  222.  * @param {string} value The query parameter value.
  223.  * @return {string} The constructed new URL.
  224.  */
  225. function setQueryParam(location, key, value) {
  226.   var query = parseQueryParams(location);
  227.   query[encodeURIComponent(key)] = encodeURIComponent(value);
  228.  
  229.   var newQuery = '';
  230.   for (var q in query) {
  231.     newQuery += (newQuery ? '&' : '?') + q + '=' + query[q];
  232.   }
  233.  
  234.   return location.origin + location.pathname + newQuery + location.hash;
  235. }
  236.  
  237. /**
  238.  * @param {Node} el A node to search for ancestors with |className|.
  239.  * @param {string} className A class to search for.
  240.  * @return {Element} A node with class of |className| or null if none is found.
  241.  */
  242. function findAncestorByClass(el, className) {
  243.   return /** @type {Element} */(findAncestor(el, function(el) {
  244.     return el.classList && el.classList.contains(className);
  245.   }));
  246. }
  247.  
  248. /**
  249.  * Return the first ancestor for which the {@code predicate} returns true.
  250.  * @param {Node} node The node to check.
  251.  * @param {function(Node):boolean} predicate The function that tests the
  252.  *     nodes.
  253.  * @return {Node} The found ancestor or null if not found.
  254.  */
  255. function findAncestor(node, predicate) {
  256.   var last = false;
  257.   while (node != null && !(last = predicate(node))) {
  258.     node = node.parentNode;
  259.   }
  260.   return last ? node : null;
  261. }
  262.  
  263. function swapDomNodes(a, b) {
  264.   var afterA = a.nextSibling;
  265.   if (afterA == b) {
  266.     swapDomNodes(b, a);
  267.     return;
  268.   }
  269.   var aParent = a.parentNode;
  270.   b.parentNode.replaceChild(a, b);
  271.   aParent.insertBefore(b, afterA);
  272. }
  273.  
  274. /**
  275.  * Disables text selection and dragging, with optional whitelist callbacks.
  276.  * @param {function(Event):boolean=} opt_allowSelectStart Unless this function
  277.  *    is defined and returns true, the onselectionstart event will be
  278.  *    surpressed.
  279.  * @param {function(Event):boolean=} opt_allowDragStart Unless this function
  280.  *    is defined and returns true, the ondragstart event will be surpressed.
  281.  */
  282. function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
  283.   // Disable text selection.
  284.   document.onselectstart = function(e) {
  285.     if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e)))
  286.       e.preventDefault();
  287.   };
  288.  
  289.   // Disable dragging.
  290.   document.ondragstart = function(e) {
  291.     if (!(opt_allowDragStart && opt_allowDragStart.call(this, e)))
  292.       e.preventDefault();
  293.   };
  294. }
  295.  
  296. /**
  297.  * TODO(dbeam): DO NOT USE. THIS IS DEPRECATED. Use an action-link instead.
  298.  * Call this to stop clicks on <a href="#"> links from scrolling to the top of
  299.  * the page (and possibly showing a # in the link).
  300.  */
  301. function preventDefaultOnPoundLinkClicks() {
  302.   document.addEventListener('click', function(e) {
  303.     var anchor = findAncestor(/** @type {Node} */(e.target), function(el) {
  304.       return el.tagName == 'A';
  305.     });
  306.     // Use getAttribute() to prevent URL normalization.
  307.     if (anchor && anchor.getAttribute('href') == '#')
  308.       e.preventDefault();
  309.   });
  310. }
  311.  
  312. /**
  313.  * Check the directionality of the page.
  314.  * @return {boolean} True if Chrome is running an RTL UI.
  315.  */
  316. function isRTL() {
  317.   return document.documentElement.dir == 'rtl';
  318. }
  319.  
  320. /**
  321.  * Get an element that's known to exist by its ID. We use this instead of just
  322.  * calling getElementById and not checking the result because this lets us
  323.  * satisfy the JSCompiler type system.
  324.  * @param {string} id The identifier name.
  325.  * @return {!HTMLElement} the Element.
  326.  */
  327. function getRequiredElement(id) {
  328.   return assertInstanceof($(id), HTMLElement,
  329.                           'Missing required element: ' + id);
  330. }
  331.  
  332. /**
  333.  * Query an element that's known to exist by a selector. We use this instead of
  334.  * just calling querySelector and not checking the result because this lets us
  335.  * satisfy the JSCompiler type system.
  336.  * @param {(!Document|!DocumentFragment|!Element)} context The context object
  337.  *     for querySelector.
  338.  * @param {string} selectors CSS selectors to query the element.
  339.  * @return {!HTMLElement} the Element.
  340.  */
  341. function queryRequiredElement(context, selectors) {
  342.   var element = context.querySelector(selectors);
  343.   return assertInstanceof(element, HTMLElement,
  344.                           'Missing required element: ' + selectors);
  345. }
  346.  
  347. // Handle click on a link. If the link points to a chrome: or file: url, then
  348. // call into the browser to do the navigation.
  349. document.addEventListener('click', function(e) {
  350.   if (e.defaultPrevented)
  351.     return;
  352.  
  353.   var el = e.target;
  354.   if (el.nodeType == Node.ELEMENT_NODE &&
  355.       el.webkitMatchesSelector('A, A *')) {
  356.     while (el.tagName != 'A') {
  357.       el = el.parentElement;
  358.     }
  359.  
  360.     if ((el.protocol == 'file:' || el.protocol == 'about:') &&
  361.         (e.button == 0 || e.button == 1)) {
  362.       chrome.send('navigateToUrl', [
  363.         el.href,
  364.         el.target,
  365.         e.button,
  366.         e.altKey,
  367.         e.ctrlKey,
  368.         e.metaKey,
  369.         e.shiftKey
  370.       ]);
  371.       e.preventDefault();
  372.     }
  373.   }
  374. });
  375.  
  376. /**
  377.  * Creates a new URL which is the old URL with a GET param of key=value.
  378.  * @param {string} url The base URL. There is not sanity checking on the URL so
  379.  *     it must be passed in a proper format.
  380.  * @param {string} key The key of the param.
  381.  * @param {string} value The value of the param.
  382.  * @return {string} The new URL.
  383.  */
  384. function appendParam(url, key, value) {
  385.   var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
  386.  
  387.   if (url.indexOf('?') == -1)
  388.     return url + '?' + param;
  389.   return url + '&' + param;
  390. }
  391.  
  392. /**
  393.  * Creates a CSS -webkit-image-set for a favicon request.
  394.  * @param {string} url The url for the favicon.
  395.  * @param {number=} opt_size Optional preferred size of the favicon.
  396.  * @param {string=} opt_type Optional type of favicon to request. Valid values
  397.  *     are 'favicon' and 'touch-icon'. Default is 'favicon'.
  398.  * @return {string} -webkit-image-set for the favicon.
  399.  */
  400. function getFaviconImageSet(url, opt_size, opt_type) {
  401.   var size = opt_size || 16;
  402.   var type = opt_type || 'favicon';
  403.   return imageset(
  404.       'chrome://' + type + '/size/' + size + '@scalefactorx/' + url);
  405. }
  406.  
  407. /**
  408.  * Creates a new URL for a favicon request for the current device pixel ratio.
  409.  * The URL must be updated when the user moves the browser to a screen with a
  410.  * different device pixel ratio. Use getFaviconImageSet() for the updating to
  411.  * occur automatically.
  412.  * @param {string} url The url for the favicon.
  413.  * @param {number=} opt_size Optional preferred size of the favicon.
  414.  * @param {string=} opt_type Optional type of favicon to request. Valid values
  415.  *     are 'favicon' and 'touch-icon'. Default is 'favicon'.
  416.  * @return {string} Updated URL for the favicon.
  417.  */
  418. function getFaviconUrlForCurrentDevicePixelRatio(url, opt_size, opt_type) {
  419.   var size = opt_size || 16;
  420.   var type = opt_type || 'favicon';
  421.   return 'chrome://' + type + '/size/' + size + '@' +
  422.       window.devicePixelRatio + 'x/' + url;
  423. }
  424.  
  425. /**
  426.  * Creates an element of a specified type with a specified class name.
  427.  * @param {string} type The node type.
  428.  * @param {string} className The class name to use.
  429.  * @return {Element} The created element.
  430.  */
  431. function createElementWithClassName(type, className) {
  432.   var elm = document.createElement(type);
  433.   elm.className = className;
  434.   return elm;
  435. }
  436.  
  437. /**
  438.  * webkitTransitionEnd does not always fire (e.g. when animation is aborted
  439.  * or when no paint happens during the animation). This function sets up
  440.  * a timer and emulate the event if it is not fired when the timer expires.
  441.  * @param {!HTMLElement} el The element to watch for webkitTransitionEnd.
  442.  * @param {number} timeOut The maximum wait time in milliseconds for the
  443.  *     webkitTransitionEnd to happen.
  444.  */
  445. function ensureTransitionEndEvent(el, timeOut) {
  446.   var fired = false;
  447.   el.addEventListener('webkitTransitionEnd', function f(e) {
  448.     el.removeEventListener('webkitTransitionEnd', f);
  449.     fired = true;
  450.   });
  451.   window.setTimeout(function() {
  452.     if (!fired)
  453.       cr.dispatchSimpleEvent(el, 'webkitTransitionEnd', true);
  454.   }, timeOut);
  455. }
  456.  
  457. /**
  458.  * Alias for document.scrollTop getter.
  459.  * @param {!HTMLDocument} doc The document node where information will be
  460.  *     queried from.
  461.  * @return {number} The Y document scroll offset.
  462.  */
  463. function scrollTopForDocument(doc) {
  464.   return doc.documentElement.scrollTop || doc.body.scrollTop;
  465. }
  466.  
  467. /**
  468.  * Alias for document.scrollTop setter.
  469.  * @param {!HTMLDocument} doc The document node where information will be
  470.  *     queried from.
  471.  * @param {number} value The target Y scroll offset.
  472.  */
  473. function setScrollTopForDocument(doc, value) {
  474.   doc.documentElement.scrollTop = doc.body.scrollTop = value;
  475. }
  476.  
  477. /**
  478.  * Alias for document.scrollLeft getter.
  479.  * @param {!HTMLDocument} doc The document node where information will be
  480.  *     queried from.
  481.  * @return {number} The X document scroll offset.
  482.  */
  483. function scrollLeftForDocument(doc) {
  484.   return doc.documentElement.scrollLeft || doc.body.scrollLeft;
  485. }
  486.  
  487. /**
  488.  * Alias for document.scrollLeft setter.
  489.  * @param {!HTMLDocument} doc The document node where information will be
  490.  *     queried from.
  491.  * @param {number} value The target X scroll offset.
  492.  */
  493. function setScrollLeftForDocument(doc, value) {
  494.   doc.documentElement.scrollLeft = doc.body.scrollLeft = value;
  495. }
  496.  
  497. /**
  498.  * Replaces '&', '<', '>', '"', and ''' characters with their HTML encoding.
  499.  * @param {string} original The original string.
  500.  * @return {string} The string with all the characters mentioned above replaced.
  501.  */
  502. function HTMLEscape(original) {
  503.   return original.replace(/&/g, '&')
  504.                  .replace(/</g, '<')
  505.                  .replace(/>/g, '>')
  506.                  .replace(/"/g, '"')
  507.                  .replace(/'/g, ''');
  508. }
  509.  
  510. /**
  511.  * Shortens the provided string (if necessary) to a string of length at most
  512.  * |maxLength|.
  513.  * @param {string} original The original string.
  514.  * @param {number} maxLength The maximum length allowed for the string.
  515.  * @return {string} The original string if its length does not exceed
  516.  *     |maxLength|. Otherwise the first |maxLength| - 1 characters with '...'
  517.  *     appended.
  518.  */
  519. function elide(original, maxLength) {
  520.   if (original.length <= maxLength)
  521.     return original;
  522.   return original.substring(0, maxLength - 1) + '\u2026';
  523. }
  524.